/**
 * ElectronExchanger Server Code File
 * 
 * File:        protocol.c
 * Brief:       BRIEF
 * Author:      Chen Kangbing
 * Email:       ckblau@outlook.com
 * Modified:    2020/09/13 09:12:58
 *
 */


#include "protocol.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


char *find_pair_splitter(char *key, char* eop, int max_len) {
    char *now, *end = eop;
    if (end > key + max_len) end = key + max_len;
    for (now = key; now < end - 1; ++now) {
        if (now[0] == ':' && now[1] == ' ')
            return now;
    }
    return NULL;
}

char *find_line_end(char *key, char* eop) {
    char *now;
    for (now = key; now < eop; ++now) {
        if (*now == '\n')
            return now;
    }
    return eop;
}

int protocol_decode(TransmissionTypeDef *ptrans, ProtoPackTypeDef *ppack) {
    char *current = ptrans->down_data;
    char *eop = ptrans->down_data + ptrans->down_data_size;
    memset(ppack, 0, sizeof(ProtoPackTypeDef));

    while (current < eop) {
        char *buf = current;
        char *key, *splitter, *value;
        int psize = ppack->pair_size;
        int value_size;
        int stop = 0;

        if (psize >= MAX_PAIR_SIZE) {
            return -1;
        }
        
        key = buf;
        splitter = find_pair_splitter(key, eop, MAX_KEY_LENGTH);
        if (splitter == NULL) return -2;
        splitter[0] = splitter[1] = 0;
        value = splitter + 2;

        if (key[0] != '#') {
            char *line_end = find_line_end(value, eop);
            value_size = line_end - value;
            if (line_end == eop) {
                stop = 1;
            }
            else {
                *line_end = 0;
                current = line_end + 1;
            }
        } else {
            value_size = eop - value;
            stop = 1;
        }

        ppack->key[psize] = key;
        ppack->value[psize] = value;
        ppack->value_size[psize] = value_size;
        ++(ppack->pair_size);
        if (stop) break;
    }
    return 0;
}

char *protocol_get_value(ProtoPackTypeDef *ppack, const char *key) {
    int size;
    return protocol_get_value_size(ppack, key, &size);
}

char *protocol_get_value_size(ProtoPackTypeDef *ppack, const char *key, int *size) {
    int i;
    for (i = 0; i < ppack->pair_size; ++i) {
        if (strcmp(key, ppack->key[i]) == 0) {
            *size = ppack->value_size[i];
            return ppack->value[i];
        }
    }
    return NULL;
}

void protocol_build_pack(ProtoPackTypeDef *ppack) {
    memset(ppack, 0, sizeof(ProtoPackTypeDef));
}

int protocol_set_value(ProtoPackTypeDef *ppack, const char *key, const char *value) {
    int value_size = strlen(value);
    return protocol_set_value_size(ppack, key, value, value_size);
}

int protocol_set_value_size(ProtoPackTypeDef *ppack, const char *key, const char *value, int value_size) {
    int cur = ppack->pair_size;
    int key_size = strlen(key);
    ppack->key[cur] = malloc(key_size + 2);
    strcpy(ppack->key[cur], key);
    ppack->value[cur] = malloc(value_size + 2);
    memcpy(ppack->value[cur], value, value_size);
    ppack->value[cur][value_size] = 0;
    ppack->value_size[cur] = value_size;
    ++(ppack->pair_size);
    return 0;
}

void protocol_encode(ProtoPackTypeDef *ppack, TransmissionTypeDef *ptrans) {
    int size = 0;
    int i;
    char *buf;
    for (i = 0; i < ppack->pair_size; ++i) {
        size += strlen(ppack->key[i]) + 2 + ppack->value_size[i];
        if (i < ppack->pair_size - 1) size += 1;
    }
    ptrans->up_data = malloc(size + 10);
    ptrans->up_data_size = size;
    buf = ptrans->up_data;
    for (i = 0; i < ppack->pair_size; ++i) {
        buf += sprintf(buf, "%s: ", ppack->key[i]);
        memcpy(buf, ppack->value[i], ppack->value_size[i]);
        buf += ppack->value_size[i];
        if (i < ppack->pair_size - 1) buf += sprintf(buf, "\n");
    }
}

void protocol_destroy_pack(ProtoPackTypeDef *ppack) {
    int i;

    for (i = 0; i < ppack->pair_size; ++i) {
        if (ppack->key[i]) free(ppack->key[i]);
        if (ppack->value[i]) free(ppack->value[i]);
    }
}
